package com.bupt.ilink.service.bailian.impl;

import com.aliyun.bailian20231229.Client;
import com.aliyun.bailian20231229.models.*;
import com.bupt.ilink.config.BailianConfig;
import com.bupt.ilink.service.bailian.FileService;
import com.bupt.ilink.tool.BailianFileTools;
import com.bupt.ilink.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class FileServiceImpl implements FileService {

    @Autowired
    AddCategoryServiceImpl addCategoryService;

    @Autowired
    ApplyFileUploadLeaseService applyFileUploadLeaseService;


    @Autowired
    AddFileService addFileService;

    @Autowired
    DescribeFileService describeFileService;

    @Autowired
    ListCategoryServiceImpl listCategoryService;

    @Autowired
    DeleteFileService deleteFileService;

    @Autowired
    ListFileService listFileService;

    @Autowired
    CreateIndexServiceImpl createIndexService;


    @Autowired
    SubmitIndexAddDocumentsJobServiceImpl submitIndexAddDocumentsJobService;

    @Autowired
    SubmitIndexJobService submitIndexJobService;

    @Autowired
    GetIndexJobStatusService getIndexJobStatusService;

    @Autowired
    DeleteIndexDocumentService deleteIndexDocumentService;

    @Autowired
    ListIndicesServiceImpl listIndicesService;

    @Autowired
    DeleteCategoryService deleteCategoryService;

    String workspaceId = BailianConfig.workspaceId;

    @Override
    public R uploadFiles(List<MultipartFile> files, String path) throws Exception {
        Client client = BailianConfig.createBailianClient();
        String categoryId = BailianFileTools.getCategoryIdByPath(path);
        String className = BailianFileTools.splitPath(path).get(1);
        List<String> successFileIds = new ArrayList<>();

        for (MultipartFile file : files){
            String fileMD5 = BailianFileTools.getMd5(file);
            ApplyFileUploadLeaseResponse response = applyFileUploadLeaseService.applyFileUploadLease(client, categoryId, file.getOriginalFilename(),  String.valueOf(file.getSize()), fileMD5, workspaceId);
            if (!BailianFileTools.checkResponse(response)){
                return R.failure("申请文件租约失败", response.getBody().getMessage());
            }
            String leaseId = response.getBody().getData().getFileUploadLeaseId();
            Map<String, String> headers = (Map<String, String>) response.getBody().getData().getParam().getHeaders();
            String bailianExtra = headers.get("X-bailian-extra");
            String contentType = headers.get("Content-Type");
            String uploadURL = response.getBody().getData().getParam().getUrl();
            String uploadResponse = BailianFileTools.uploadFile(uploadURL, file, bailianExtra, contentType);
            if (Objects.equals(uploadResponse, "failed")){
                return R.failure("文件上传失败", response.getBody().getMessage());
            }
            AddFileResponse addFileResponse = addFileService.addFile(client, leaseId, "DASHSCOPE_DOCMIND", categoryId, workspaceId);
            if (!BailianFileTools.checkResponse(addFileResponse)){
                return R.failure("添加文件失败", response.getBody().getMessage());
            }
            String fileId = addFileResponse.getBody().getData().getFileId();
            System.out.println("文件正在添加");
            String status;
            do {
                DescribeFileResponse fileResponse = describeFileService.getDescribeFile(client, workspaceId, fileId);
                if (!BailianFileTools.checkResponse(fileResponse)){
                    return R.failure("获取文件信息失败", fileResponse.getBody().getMessage());
                }
                status = fileResponse.getBody().getData().getStatus();
                if (Objects.equals(status, "PARSE_FAILED")) {
                    return R.failure("文件添加失败", fileResponse.getBody().getMessage());
                }
                System.out.println("文件解析中");
                Thread.sleep(20000);
            } while (!Objects.equals(status, "PARSE_SUCCESS"));
            successFileIds.add(fileId);
        }
        ListIndicesResponse listIndicesResponse = listIndicesService.listIndices(client, className, workspaceId);
        if (!BailianFileTools.checkResponse(listIndicesResponse)){
            return R.failure("获取索引列表失败", listIndicesResponse.getBody().getMessage());
        }
        String indexId = BailianFileTools.getIndexIdByName(listIndicesResponse, className);
        if (indexId == null){
            CreateIndexResponse indexWithDoc = createIndexService.createIndexWithDoc(client, workspaceId, className, "unstructured", successFileIds, "DEFAULT");
            if (!BailianFileTools.checkResponse(indexWithDoc)){
                return R.failure("创建索引接口调用失败", indexWithDoc.getBody().getMessage());
            }
            indexId = indexWithDoc.getBody().getData().getId();
            System.out.println(indexId);
            SubmitIndexJobResponse submitIndexJobResponse = submitIndexJobService.submitIndexJob(client, workspaceId, indexId);
            if (!BailianFileTools.checkResponse(submitIndexJobResponse)){
                return R.failure("提交索引任务接口调用失败", submitIndexJobResponse.getBody().getMessage());
            }
            String jobId = submitIndexJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }
                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));
        }   else{
            SubmitIndexAddDocumentsJobResponse submitIndexAddDocumentsJobResponse = submitIndexAddDocumentsJobService.submitIndexAddDocumentsJob(client, workspaceId, indexId, successFileIds);
            if (!BailianFileTools.checkResponse(submitIndexAddDocumentsJobResponse)){
                return R.failure("索引追加接口调用失败", submitIndexAddDocumentsJobResponse.getBody().getMessage());
            }

            String jobId = submitIndexAddDocumentsJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }

                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));

        }
        return R.ok("文件上传结束", successFileIds);
    }

    @Override
    public R uploadFile(MultipartFile file, String path,String rename) throws Exception {
        Client client = BailianConfig.createBailianClient();
        String categoryId = BailianFileTools.getCategoryIdByPath(path);
        String className = BailianFileTools.splitPath(path).get(1);

        String fileMD5 = BailianFileTools.getMd5(file);
        ApplyFileUploadLeaseResponse response= new ApplyFileUploadLeaseResponse() ;
        if (rename.isEmpty()){
            response = applyFileUploadLeaseService.applyFileUploadLease(client, categoryId, file.getOriginalFilename(),  String.valueOf(file.getSize()), fileMD5, workspaceId);
        }else{
            response = applyFileUploadLeaseService.applyFileUploadLease(client, categoryId, rename,  String.valueOf(file.getSize()), fileMD5, workspaceId);

        }
        if (!BailianFileTools.checkResponse(response)){
            return R.failure("申请文件租约失败", response.getBody().getMessage());
        }
        String leaseId = response.getBody().getData().getFileUploadLeaseId();
        Map<String, String> headers = (Map<String, String>) response.getBody().getData().getParam().getHeaders();
        String bailianExtra = headers.get("X-bailian-extra");
        String contentType = headers.get("Content-Type");
        String uploadURL = response.getBody().getData().getParam().getUrl();
        String uploadResponse = BailianFileTools.uploadFile(uploadURL, file, bailianExtra, contentType);
        if (Objects.equals(uploadResponse, "failed")){
            return R.failure("文件上传失败", response.getBody().getMessage());
        }
        AddFileResponse addFileResponse = addFileService.addFile(client, leaseId, "DASHSCOPE_DOCMIND", categoryId, workspaceId);
        if (!BailianFileTools.checkResponse(addFileResponse)){
            return R.failure("添加文件失败", response.getBody().getMessage());
        }
        String fileId = addFileResponse.getBody().getData().getFileId();
        System.out.println("文件正在添加");
        String status;
        do {
            DescribeFileResponse fileResponse = describeFileService.getDescribeFile(client, workspaceId, fileId);
            if (!BailianFileTools.checkResponse(fileResponse)){
                return R.failure("获取文件信息失败", fileResponse.getBody().getMessage());
            }
            status = fileResponse.getBody().getData().getStatus();
            if (Objects.equals(status, "PARSE_FAILED")) {
                return R.failure("文件添加失败", fileResponse.getBody().getMessage());
            }
            System.out.println("文件解析中");
            Thread.sleep(20000);
        } while (!Objects.equals(status, "PARSE_SUCCESS"));
        String successFileId = fileId;
        ListIndicesResponse listIndicesResponse = listIndicesService.listIndices(client, className, workspaceId);
        if (!BailianFileTools.checkResponse(listIndicesResponse)){
            return R.failure("获取索引列表失败", listIndicesResponse.getBody().getMessage());
        }
        String indexId = BailianFileTools.getIndexIdByName(listIndicesResponse, className);
        if (indexId == null){
            CreateIndexResponse indexWithDoc = createIndexService.createIndexWithDoc(client, workspaceId, className, "unstructured", Collections.singletonList(successFileId), "DEFAULT");
            if (!BailianFileTools.checkResponse(indexWithDoc)){
                return R.failure("创建索引接口调用失败", indexWithDoc.getBody().getMessage());
            }
            indexId = indexWithDoc.getBody().getData().getId();
            System.out.println(indexId);
            SubmitIndexJobResponse submitIndexJobResponse = submitIndexJobService.submitIndexJob(client, workspaceId, indexId);
            if (!BailianFileTools.checkResponse(submitIndexJobResponse)){
                return R.failure("提交索引任务接口调用失败", submitIndexJobResponse.getBody().getMessage());
            }
            String jobId = submitIndexJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }
                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));
        }   else{
            SubmitIndexAddDocumentsJobResponse submitIndexAddDocumentsJobResponse = submitIndexAddDocumentsJobService.submitIndexAddDocumentsJob(client, workspaceId, indexId, Collections.singletonList(successFileId));
            if (!BailianFileTools.checkResponse(submitIndexAddDocumentsJobResponse)){
                return R.failure("索引追加接口调用失败", submitIndexAddDocumentsJobResponse.getBody().getMessage());
            }

            String jobId = submitIndexAddDocumentsJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }

                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));

        }
        return R.ok("文件上传结束");
    }

    @Override
    public R uploadFile(File file, String path, String rename) throws Exception {

        Client client = BailianConfig.createBailianClient();
        String categoryId = BailianFileTools.getCategoryIdByPath(path);
        String className = BailianFileTools.splitPath(path).get(1);

        String fileMD5 = BailianFileTools.getMd5(file);
        ApplyFileUploadLeaseResponse response= new ApplyFileUploadLeaseResponse() ;
        if (rename.isEmpty()){
            response = applyFileUploadLeaseService.applyFileUploadLease(client, categoryId, file.getName(),  String.valueOf(file.length()), fileMD5, workspaceId);
        }else{
            response = applyFileUploadLeaseService.applyFileUploadLease(client, categoryId, rename,  String.valueOf(file.length()), fileMD5, workspaceId);

        }
        if (!BailianFileTools.checkResponse(response)){
            return R.failure("申请文件租约失败", response.getBody().getMessage());
        }
        String leaseId = response.getBody().getData().getFileUploadLeaseId();
        Map<String, String> headers = (Map<String, String>) response.getBody().getData().getParam().getHeaders();
        String bailianExtra = headers.get("X-bailian-extra");
        String contentType = headers.get("Content-Type");
        String uploadURL = response.getBody().getData().getParam().getUrl();
        String uploadResponse = BailianFileTools.uploadFile(uploadURL, file, bailianExtra, contentType);
        if (Objects.equals(uploadResponse, "failed")){
            return R.failure("文件上传失败", response.getBody().getMessage());
        }
        AddFileResponse addFileResponse = addFileService.addFile(client, leaseId, "DASHSCOPE_DOCMIND", categoryId, workspaceId);
        if (!BailianFileTools.checkResponse(addFileResponse)){
            return R.failure("添加文件失败", response.getBody().getMessage());
        }
        String fileId = addFileResponse.getBody().getData().getFileId();
        System.out.println("文件正在添加");
        String status;
        do {
            DescribeFileResponse fileResponse = describeFileService.getDescribeFile(client, workspaceId, fileId);
            if (!BailianFileTools.checkResponse(fileResponse)){
                return R.failure("获取文件信息失败", fileResponse.getBody().getMessage());
            }
            status = fileResponse.getBody().getData().getStatus();
            if (Objects.equals(status, "PARSE_FAILED")) {
                return R.failure("文件添加失败", fileResponse.getBody().getMessage());
            }
            System.out.println("文件解析中");
            Thread.sleep(20000);
        } while (!Objects.equals(status, "PARSE_SUCCESS"));
        String successFileId = fileId;
        ListIndicesResponse listIndicesResponse = listIndicesService.listIndices(client, className, workspaceId);
        if (!BailianFileTools.checkResponse(listIndicesResponse)){
            return R.failure("获取索引列表失败", listIndicesResponse.getBody().getMessage());
        }
        String indexId = BailianFileTools.getIndexIdByName(listIndicesResponse, className);
        if (indexId == null){
            CreateIndexResponse indexWithDoc = createIndexService.createIndexWithDoc(client, workspaceId, className, "unstructured", Collections.singletonList(successFileId), "DEFAULT");
            if (!BailianFileTools.checkResponse(indexWithDoc)){
                return R.failure("创建索引接口调用失败", indexWithDoc.getBody().getMessage());
            }
            indexId = indexWithDoc.getBody().getData().getId();
            System.out.println(indexId);
            SubmitIndexJobResponse submitIndexJobResponse = submitIndexJobService.submitIndexJob(client, workspaceId, indexId);
            if (!BailianFileTools.checkResponse(submitIndexJobResponse)){
                return R.failure("提交索引任务接口调用失败", submitIndexJobResponse.getBody().getMessage());
            }
            String jobId = submitIndexJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }
                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));
        }   else{
            SubmitIndexAddDocumentsJobResponse submitIndexAddDocumentsJobResponse = submitIndexAddDocumentsJobService.submitIndexAddDocumentsJob(client, workspaceId, indexId, Collections.singletonList(successFileId));
            if (!BailianFileTools.checkResponse(submitIndexAddDocumentsJobResponse)){
                return R.failure("索引追加接口调用失败", submitIndexAddDocumentsJobResponse.getBody().getMessage());
            }

            String jobId = submitIndexAddDocumentsJobResponse.getBody().getData().getId();
            String totalStatus;
            do {
                GetIndexJobStatusResponse indexJobStatus = getIndexJobStatusService.getIndexJobStatus(client, workspaceId, jobId, indexId);
                if (!BailianFileTools.checkResponse(indexJobStatus)){
                    return R.failure("获取索引任务状态失败", indexJobStatus.getBody().getMessage());
                }

                totalStatus = indexJobStatus.getBody().getData().getStatus();
                if (!Objects.equals(totalStatus, "COMPLETED")){
                    indexJobStatus.getBody().getData().getDocuments().forEach(document -> {
                        System.out.println(document.getDocName() + " " + document.getStatus());
                    });
                }
                Thread.sleep(5000);
            } while (!Objects.equals(totalStatus, "COMPLETED"));

        }
        return R.ok("文件上传结束");
    }

    @Override
    public R createCategory(String path, String directory) throws Exception {
        com.aliyun.bailian20231229.Client client = BailianConfig.createBailianClient();
        String dirctoryName = BailianFileTools.splitPath(directory).get(0);
        if (Objects.equals(path, "/") || Objects.equals(path, "")){
            System.out.println(workspaceId);
            AddCategoryResponse response = addCategoryService.addCategory(client, workspaceId, dirctoryName, "UNSTRUCTURED");
            if (!BailianFileTools.checkResponse(response)){
                return R.failure("添加类目失败", response.getBody().getMessage());
            }
            return R.ok("添加类目成功");
        }
        String parentCategoryId = BailianFileTools.getCategoryIdByPath(path);

        AddCategoryResponse response = addCategoryService.addCategory(client, workspaceId, dirctoryName, "UNSTRUCTURED", parentCategoryId);
        if (!BailianFileTools.checkResponse(response)){
            return R.failure("添加类目失败", response.getBody().getMessage());
        }
        return R.ok("添加类目成功");
    }

    @Override
    public R deleteFile(String path, String fileName) throws Exception {
        com.aliyun.bailian20231229.Client client = BailianConfig.createBailianClient();
        String categoryId = BailianFileTools.getCategoryIdByPath(path);
        String className = BailianFileTools.splitPath(path).get(1);
        ListFileResponse listFileResponse = listFileService.listfile(client, categoryId, workspaceId);
        if (!BailianFileTools.checkResponse(listFileResponse)){
            return R.failure("获取文件列表失败", listFileResponse.getBody().getMessage());
        }
        String fileId = BailianFileTools.getFileIdByName(listFileResponse, fileName);
        System.out.println(fileId);
        DeleteFileResponse deleteFileResponse = deleteFileService.deleteFile(client, fileId, workspaceId);
        if (!BailianFileTools.checkResponse(deleteFileResponse)){
            return R.failure("删除文件失败", deleteFileResponse.getBody().getMessage());
        }
        ListIndicesResponse listIndicesResponse = listIndicesService.listIndices(client, className, workspaceId);
        String indexId = BailianFileTools.getIndexIdByName(listIndicesResponse, className);
        DeleteIndexDocumentResponse deleteIndexDocumentResponse = deleteIndexDocumentService.deleteIndexDocument(client, workspaceId, indexId, Collections.singletonList(fileId));
        if (!BailianFileTools.checkResponse(deleteIndexDocumentResponse)){
            return R.failure("删除索引文档失败", deleteIndexDocumentResponse.getBody().getMessage());
        }
        return R.ok("删除文件成功");
    }

    @Override
    public R deleteCategory(String path) throws Exception {
        com.aliyun.bailian20231229.Client client = BailianConfig.createBailianClient();
        String categoryId = BailianFileTools.getCategoryIdByPath(path);
        ListCategoryResponse listCategoryResponse = listCategoryService.listCategory(client, workspaceId, "UNSTRUCTURED", categoryId);
        if (!BailianFileTools.checkResponse(listCategoryResponse)){
            return R.failure("获取类目列表失败", listCategoryResponse.getBody().getMessage());
        }
        AtomicReference<String> newPath = new AtomicReference<>(path);
        final String finalpath = newPath.get();
        if (listCategoryResponse.getBody().getData().getCategoryList().size() != 0){
            listCategoryResponse.getBody().getData().getCategoryList().forEach(category->{
                try {
                    Thread.sleep(500);
                    deleteCategory(finalpath + category.getCategoryName() + "/");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
        String className = BailianFileTools.splitPath(path).get(1);
        ListFileResponse listFileResponse = listFileService.listfile(client, categoryId, workspaceId);
        if (!BailianFileTools.checkResponse(listFileResponse)){
            return R.failure("获取文件列表失败", listFileResponse.getBody().getMessage());
        }
        List<String> allFileIds = BailianFileTools.getAllFileIds(listFileResponse);
        if (allFileIds.size() != 0){
            ListIndicesResponse listIndicesResponse = listIndicesService.listIndices(client, className, workspaceId);
            String indexId = BailianFileTools.getIndexIdByName(listIndicesResponse, className);
            DeleteIndexDocumentResponse deleteIndexDocumentResponse = deleteIndexDocumentService.deleteIndexDocument(client, workspaceId, indexId, allFileIds);
            if (!BailianFileTools.checkResponse(deleteIndexDocumentResponse)){
                return R.failure("删除索引文档失败", deleteIndexDocumentResponse.getBody().getMessage());
            }
            for (String fileId : allFileIds){
                DeleteFileResponse deleteFileResponse = deleteFileService.deleteFile(client, fileId, workspaceId);
                if (!BailianFileTools.checkResponse(deleteFileResponse)){
                    return R.failure("删除文件失败", deleteFileResponse.getBody().getMessage());
                }
            }
        }
        DeleteCategoryResponse deleteCategoryResponse = deleteCategoryService.deleteCategory(client, categoryId, workspaceId);
        if (!BailianFileTools.checkResponse(deleteCategoryResponse)){
            return R.failure("删除类目失败", deleteCategoryResponse.getBody().getMessage());
        }
        return R.ok("删除类目成功");
    }
}
